package yawning.mew.cat;

import yawning.mew.ProcEffect.Trigger;
import yawning.mew.cat.CatModelSimState.CatTargetData;
import yawning.mew.cat.CatModelSimulation.SimulatorProperty;
import yawning.mew.character.CharacterModel.AttackResult;
import yawning.mew.sim.SimulationAction;
import yawning.mew.sim.SimulationTarget;

public class FerociousBiteAction implements SimulationAction {
	CatModelSimState mState;
	private SimulationTarget mTarget;
	private CatTargetData mTargetData;
	private String mTargetName;

	FerociousBiteAction(CatModelSimState state, CatTargetData targetData) {
		mState = state;
		mTarget = targetData.getSimulationTarget();
		mTargetData = targetData;
		mTargetName = mTarget.getTarget().getName();
	}

	public double perform() {
		int cps = mState.getComboPoints();
		int cost = mState.getEnergyCost(mState.mModel.biteCost);
		if ((mState.getEnergy() < cost && !mState.isOoCUp()) || mState.getComboPoints() == 0) return SimulationAction.ACTION_FAIL;
		int prevEnergy = mState.getEnergy();

		double pBonusCrit = 0;
		if (mState.mSimEngine.getConfig().getBool(SimulatorProperty.ASSUMEEXTERNALBLEED) || mTargetData.mRakeAction.isUp() || mTargetData.mRipAction.isUp()) {
			pBonusCrit = mState.mModel.pBonusBiteCrit;
		}

		AttackResult result = (mTargetData.mCanParry) ? mState.mModel.getFrontalYellowResult(pBonusCrit) : mState.mModel.getYellowResult(pBonusCrit);

		if (result == AttackResult.MISS) {
			cost = (int) Math.round(cost * 0.2);
			mNrBiteMiss++;

			if (mState.mIsLogging) mState.mLog.log("Ferocious Bite: %s MISS\n", mTargetName);
		} else if (result == AttackResult.DODGE) {
			cost = (int) Math.round(cost * 0.2);
			mNrBiteDodge++;

			if (mState.mIsLogging) mState.mLog.log("Ferocious Bite: %s DODGE\n", mTargetName);
		} else if (result == AttackResult.PARRY) {
			cost = (int) Math.round(cost * 0.2);
			mNrBiteParry++;

			if (mState.mIsLogging) mState.mLog.log("Ferocious Bite: %s PARRY\n", mTargetName);
		} else {
			double damage = mState.mModel.levelDep.getFBBaseDmg() + mState.mModel.levelDep.getFBCpDmg() * cps + mState.mModel.getAttackPower() * mState.mModel.levelDep.getFBCoeff() * cps;

			// Handle the extra energy conversion mechanic.
			int baseCost = (mState.mOocEv.isUp()) ? 0 : cost;
			int extraEnergy = Math.min(mState.mModel.biteCost, mState.getEnergy() - baseCost);

			mBiteEnergy += mState.onEnergyConsumer(extraEnergy); // Subtract extra energy here.
			damage *= 1.0 + (double) extraEnergy / mState.mModel.biteCost;
			mBiteExtraEnergy += extraEnergy;

			if (result == AttackResult.CRIT) {
				mNrBiteCrit++;
				damage *= mState.mModel.multCrit;
			} else {
				mNrBiteHit++;
			}

			damage *= mState.mModel.multBiteFeralAggression;
			damage *= mState.getDirectDamageMult();
			mBiteDamage += Math.round(damage);

			if (mState.mIsLogging) mState.mLog.log("Ferocious Bite: %s %s Damage: %d\n", mTargetName, result, Math.round(damage));

			if (result == AttackResult.CRIT) mState.mSimEngine.triggerProc(mTarget, Trigger.YELLOWCRIT); else mState.mSimEngine.triggerProc(mTarget, Trigger.YELLOW);

			// Handle Blood in the Water
			if (mTargetData.mRipAction.isUp() && mState.isInBloodInTheWaterRange() && mState.mModel.pBloodInTheWater > 0.0) {
				mTargetData.mRipAction.onBite();
			}

			mNrBiteCPs += cps;

			mState.mBerserkEv.onTier12_4pc_tigger(cps);
			mState.onFinisher();
		}

		if (mState.mOocEv.isUp()) mNrBiteOoC++;
		if (mState.mTigersFuryEv.isUp()) mNrBiteTF++;

		mBiteEnergy += mState.onOoCConsumer(cost);

		mState.logResourceChange(prevEnergy, cps);

		return 1.0f;
	}

	public void onBitW() {
		mNrBiteBase = mNrBiteMiss + mNrBiteDodge + mNrBiteParry +  mNrBiteCrit + mNrBiteHit;
	}

	long mBiteDamage;
	long mBiteExtraEnergy;
	int mNrBiteMiss;
	int mNrBiteDodge;
	int mNrBiteParry;
	int mNrBiteCrit;
	int mNrBiteHit;

	int mNrBiteBase;

	int mBiteEnergy;
	int mNrBiteCPs;
	int mNrBiteOoC;
	int mNrBiteTF;
}
